package cn.com.enersun.iec61850.sclparse;

import cn.com.enersun.iec61850.web.domain.ConnectModelByScl;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;

import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;
//import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lionel on 2017/3/15.
 */
public class ScdParse {

    private static final Logger logger = LoggerFactory.getLogger(ScdParse.class);

    public static void main(String[] args) throws IOException {
        if (args.length != 1) {
            System.out.println("usage: cn.com.enersun.iec61850.sclparse.ScdParse <scd-file>");
            return;
        }
        SAXReader reader = new SAXReader();

        Map<String, String> map = new HashMap<String, String>();
        map.put("ns", "http://www.iec.ch/61850/2003/SCL");
        map.put("sf", "http://www.sifang.com");
        reader.getDocumentFactory().setXPathNamespaceURIs(map);

        //待解析的文件
//        URL srcUrl = ClassLoader.getSystemResource("云电科技园200EA.scd");
//        Document document = reader.read(srcUrl);

        //验证scl文件的有效性
        if (!validateXMLSchema("SCL/SCL.xsd", args[0])) {
            return;
        }

        Document document = null;
        try {
            document = reader.read(args[0]);
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println(args[0] + " parse failed!");
        }

        //找到ied节点的个数
        List<Element> iedNodes = document.selectNodes("//ns:IED");
        System.out.println("IED count is : " + iedNodes.size());

        for (Element ied : iedNodes) {
            String iedName = ied.attributeValue("name");

//            String destFileName = ScdParse.class.getResource("/").getPath() + iedName + ".icd";
            String destFileName = iedName + ".icd";
            //复制一份新的scd文件，文件名为ied的name属性值，并修改该文件
//            if (copyFile(srcUrl.getPath(), destFileName, true)) {
            if (copyFile(args[0], destFileName, true)) {
                //删除节点
                Document documentItem = null;
                try {
                    documentItem = reader.read(destFileName);
                } catch (DocumentException e) {
                    e.printStackTrace();
                    System.out.println(args[0] + " parse failed!");
                }
                List<Element> deleteNodes = documentItem.selectNodes("//ns:ConnectedAP[@iedName!='"+ iedName +"'] | //sf:SF_IED[@name!='"+ iedName +"'] | //ns:IED[@name!='"+ iedName +"']");
                for (Element deleteNode: deleteNodes) {
                    //获取父元素，使用父元素删除指定子元素
                    deleteNode.getParent().remove(deleteNode);
                }
                //指定文件输出的位置
                FileOutputStream out = new FileOutputStream(destFileName);
                //1.创建写出对象
                XMLWriter writer=new XMLWriter(out);
                //2.写出Document对象
                writer.write(documentItem);
                //3.关闭流
                writer.close();

                System.out.println(args[0] + " parse successful!");
            }


        }
    }

    /**
     * 复制单个文件
     *
     * @param srcFileName
     *            待复制的文件名
     * @param destFileName
     *            目标文件名
     * @param overlay
     *            如果目标文件存在，是否覆盖
     * @return 如果复制成功返回true，否则返回false
     */
    public static boolean copyFile(String srcFileName, String destFileName, boolean overlay) throws UnsupportedEncodingException {
        // utf-8的编码解码为中文
        srcFileName = URLDecoder.decode(srcFileName, "utf-8");
        File srcFile = new File(srcFileName);
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            System.out.println("源文件：" + srcFileName + "不存在！");
            return false;
        } else if (!srcFile.isFile()) {
            System.out.println("复制文件失败，源文件：" + srcFileName + "不是一个文件！");
            return false;
        }

        // 判断目标文件是否存在
        File destFile = new File(destFileName);
        if (destFile.exists()) {
            // 如果目标文件存在并允许覆盖
            if (overlay) {
                // 删除已经存在的目标文件，无论目标文件是目录还是单个文件
                new File(destFileName).delete();
            }
        } else {
            // 如果目标文件所在目录不存在，则创建目录
            if (destFile.getParentFile() != null && !destFile.getParentFile().exists()) {
                // 目标文件所在目录不存在
                if (!destFile.getParentFile().mkdirs()) {
                    // 复制文件失败：创建目标文件所在目录失败
                    return false;
                }
            }
        }

        // 复制文件
        int byteread = 0; // 读取的字节数
        InputStream in = null;
        OutputStream out = null;

        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            byte[] buffer = new byte[1024];

            while ((byteread = in.read(buffer)) != -1) {
                out.write(buffer, 0, byteread);
            }
            return true;
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            return false;
        } finally {
            try {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 验证xml文件是否符合xsd的规范
     * @param xsdPath
     * @param xmlPath
     * @return
     */
    public static boolean validateXMLSchema(String xsdPath, String xmlPath){
        try {
            // utf-8的编码解码为中文
            xmlPath = URLDecoder.decode(xmlPath, "utf-8");
            SchemaFactory factory =
                    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = factory.newSchema(new File(xsdPath));
            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(xmlPath)));
        } catch (IOException | SAXException e) {
            System.out.println("InvalidXMLException: "+e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 转换成Icd文件
     * @param sclPath scl文件路径
     * @param icdFileDirPath icd文件存放目录
     * @return
     * @throws IOException
     */
    public static List<ConnectModelByScl> transferToIcd(String sclPath, String icdFileDirPath) throws IOException{
        List<ConnectModelByScl> icds = new ArrayList<>();

        SAXReader reader = new SAXReader();

        Map<String, String> map = new HashMap<String, String>();
        map.put("ns", "http://www.iec.ch/61850/2003/SCL");
        map.put("sf", "http://www.sifang.com");
        reader.getDocumentFactory().setXPathNamespaceURIs(map);

        Document document = null;
        try {
            document = reader.read(new File(sclPath));
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println(sclPath + " parse failed!");
        }

        //找到ied节点的个数
        List<Element> iedNodes = document.selectNodes("//ns:IED");
//        List<Element> sfIedNodes = document.selectNodes("//sf:SF_IED");
        System.out.println("IED count is : " + iedNodes.size());

        for (Element ied : iedNodes) {
            String iedName = ied.attributeValue("name");
            //获取ip
            Element ipElement = (Element)document.selectSingleNode("//ns:ConnectedAP[@iedName='"+ iedName +"']/ns:Address/ns:P[@type='IP']");
            String ip = ipElement.getTextTrim();
            //获取
            Element portElement = (Element)document.selectSingleNode("//ns:ConnectedAP[@iedName='"+ iedName +"']/ns:Address/ns:P[@type='PORT']");
            String port = "102";
            if (portElement != null)
                port = portElement.getTextTrim();

//            String destFileName = ScdParse.class.getResource("/").getPath() + iedName + ".icd";
            String destFileName = icdFileDirPath + "/" + iedName + ".icd";
            //复制一份新的scd文件，文件名为ied的name属性值，并修改该文件
//            if (copyFile(srcUrl.getPath(), destFileName, true)) {
            if (copyFile(sclPath, destFileName, true)) {
                //删除节点
                Document documentItem = null;
                try {
                    documentItem = reader.read(destFileName);
                } catch (DocumentException e) {
                    e.printStackTrace();
                    System.out.println(sclPath + " parse failed!");
                }
                List<Element> deleteNodes = documentItem.selectNodes("//ns:ConnectedAP[@iedName!='"+ iedName +"'] | //sf:SF_IED[@name!='"+ iedName +"'] | //ns:IED[@name!='"+ iedName +"']");
                for (Element deleteNode: deleteNodes) {
                    //获取父元素，使用父元素删除指定子元素
                    deleteNode.getParent().remove(deleteNode);
                }
                //指定文件输出的位置
                FileOutputStream out = new FileOutputStream(destFileName);
                //1.创建写出对象
                XMLWriter writer=new XMLWriter(out);
                //2.写出Document对象
                writer.write(documentItem);
                //3.关闭流
                writer.close();

                System.out.println(sclPath + " parse successful!");
            }
            ConnectModelByScl icd = new ConnectModelByScl(ip, iedName, destFileName, port);
            icds.add(icd);
        }

        return icds;
    }

    /**
     * 验证scd文件是否符合规范
     * @param args
     * @throws IOException
     */
//    public static void main(String[] args) throws IOException {
//
//        //待解析的文件
//        URL srcUrl = ClassLoader.getSystemResource("云电科技园sun5PCS.scd");
//        URL xsdUrl = ClassLoader.getSystemResource("SCL/SCL.xsd");
//
//        //验证scl文件的有效性
//        if (!validateXMLSchema(xsdUrl.getPath(), srcUrl.getPath())) {
//            return;
//        }
//    }
}
